package de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.nodeImpl;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.espertech.esper.client.EPServiceProvider;

import de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.MMOperatorNode;
import de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.NodeFactory;
import de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.NodeFactoryManager;

public class LessOrEqualNodeFactory implements NodeFactory {

	public MMOperatorNode createNode(Element DOMElement,
			Element attachmentsElement, MMOperatorNode parent,
			EPServiceProvider EPService) {

		Element attachment = null;
		NodeList attachments = attachmentsElement
				.getElementsByTagName("attachment");
		for (int i = 0; i < attachments.getLength(); i++) {
			if (((Element) attachments.item(i))
					.getAttributeNode("attachmentID").getNodeValue().equals(
							DOMElement.getAttributeNode("attachmentID")
									.getNodeValue())) {
				attachment = (Element) attachments.item(i);
			}
		}

		MMOperatorNode toReturn = new MMOperatorNode();

		// Attributes independent of the children
		toReturn.setOutputStreamName("lessOrEqual"
				+ (++MMOperatorNode.nodeLatestDistributedID));
		toReturn.setOutputMetric("lessOrEqual");

		toReturn.setParent(parent);

		/*
		 * Parameters to get : activityID or processID activityStartEventName or
		 * processStartEventName activityEndEventName or processEndEventName
		 */
		// toReturn.setParameters();
		// Children nodes not for atomic operators like state, duration,
		// count...
		NodeList childrenElements = DOMElement.getChildNodes();
		if (childrenElements.getLength() > 0) {
			List<MMOperatorNode> children = new ArrayList<MMOperatorNode>(4);
			for (int i = 0; i < childrenElements.getLength(); i++) {
				Element currentChildRoot = (Element) childrenElements.item(i);
				children.add(NodeFactoryManager.getInstance(
						currentChildRoot.getLocalName()).createNode(
						currentChildRoot, attachmentsElement, toReturn,
						EPService));
			}

			toReturn.setChildren(children);
		}

		String statementString = new String();
		String statementForFilter1String = new String();
		String statementForFilter2String = new String();

		if (toReturn.getChildren().size() == 3) {
			statementForFilter1String
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "Correlation1"
							+ " SELECT "
							+ " a.*,"
							+ " b.correlationSet AS correlationSetFromCorrelation "
							+ " FROM PATTERN [(every a = "
							+ toReturn.getChildren().get(0)
									.getOutputStreamName()
							+ " -> b = "
							+ toReturn.getChildren().get(2)
									.getOutputStreamName()
							+ "(de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.isSetIntersectionNonEmpty(a.correlationSet, b.correlationSet)) OR "
							+ " ( every b = "
							+ toReturn.getChildren().get(2)
									.getOutputStreamName()
							+ " -> "
							+ "a = "
							+ toReturn.getChildren().get(0)
									.getOutputStreamName()
							+ "(de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.isSetIntersectionNonEmpty(a.correlationSet, b.correlationSet))"
							+ ")]");

			statementForFilter2String
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "Correlation2"
							+ " SELECT "
							+ " a.*,"
							+ " b.correlationSet AS correlationSetFromCorrelation "
							+ " FROM PATTERN [(every a = "
							+ toReturn.getChildren().get(1)
									.getOutputStreamName()
							+ " -> b = "
							+ toReturn.getChildren().get(2)
									.getOutputStreamName()
							+ "(de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.isSetIntersectionNonEmpty(a.correlationSet, b.correlationSet)) OR "
							+ " ( every b = "
							+ toReturn.getChildren().get(2)
									.getOutputStreamName()
							+ " -> "
							+ "a = "
							+ toReturn.getChildren().get(1)
									.getOutputStreamName()
							+ "(de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.isSetIntersectionNonEmpty(a.correlationSet, b.correlationSet))"
							+ ")]");

			statementString
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "SELECT a.timestamp <= b.timestamp AS "
							+ toReturn.getOutputMetric()
							+ ", "
							+ "de.unistuttgart.kpimonitoring.esper.eventmanagement.EventUtils.addInCorrelation(a.correlationSet, b.correlationSet) AS correlationSet FROM PATTERN [(every a = "
							+ toReturn.getOutputStreamName()
							+ "correlation1 -> b = "
							+ toReturn.getOutputStreamName()
							+ "correlation2(correlationSetFromCorrelation = a.correlationSetFromCorrelation)) OR"
							+ "(every b = "
							+ toReturn.getOutputStreamName()
							+ "correlation2 -> a = "
							+ toReturn.getOutputStreamName()
							+ "correlation1(correlationSetFromCorrelation = b.correlationSetFromCorrelation))");
		} else {
			statementString
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "SELECT a.timestamp <= b.timestamps AS "
							+ toReturn.getOutputMetric()
							+ ", "
							+ "de.unistuttgart.kpimonitoring.esper.eventmanagement.EventUtils.addInCorrelation(a.correlationSet, b.correlationSet) AS correlationSet FROM PATTERN [(every a = "
							+ toReturn.getChildren().get(0)
									.getOutputStreamName()
							+ " -> b = "
							+ toReturn.getChildren().get(1)
									.getOutputStreamName()
							+ "(de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.isSetIntersectionNonEmpty(correlationSet, a.correlationSet)) ) OR "
							+ "((every b = "
							+ toReturn.getChildren().get(1)
									.getOutputStreamName()
							+ " -> a = "
							+ toReturn.getChildren().get(0)
									.getOutputStreamName()
							+ "(de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.isSetIntersectionNonEmpty(correlationSet, b.correlationSet)))"
					);
		}

		// Creation of the statements that are directly registered in the engine
		// !
		toReturn.setStatement(EPService.getEPAdministrator().createEPL(
				statementForFilter1String));
		toReturn.setStatement(EPService.getEPAdministrator().createEPL(
				statementForFilter2String));
		toReturn.setStatement(EPService.getEPAdministrator().createEPL(
				statementString));

		return toReturn;
	}

}
